package com.example.myapplication.widgets.pickerview.date_time;

import android.annotation.SuppressLint;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;

import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;

import com.example.myapplication.R;
import com.example.myapplication.utils.CollectionUtils;
import com.example.myapplication.utils.TimeUtils;
import com.example.myapplication.widgets.pickerview.base.StringPickerBean;
import com.example.myapplication.widgets.pickerview.base.PickerBean;
import com.example.myapplication.widgets.pickerview.base.PickerView;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

public class DateTimePickerView extends ConstraintLayout {
    private PickerView mDatePicker;
    private PickerView mHourPicker;
    private PickerView mMinutePicker;

    private int[] mStartDayInfo, mEndDayInfo; //上限下限时间
    private int[] mSelectedDayInfo; //当前选择的时间
    private boolean isIncludeCurrentDay = true; //时间列表是否要包含今天
    private int mPreDatePosition, mPreHourPosition;
    private OnSelectedListener mOnSelectedListener;

    private boolean isShowDate;

    public DateTimePickerView(Context context) {
        this(context, null);
    }

    public DateTimePickerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DateTimePickerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        View view = View.inflate(context, R.layout.layout_date_time_picker_view, this);
        mDatePicker = view.findViewById(R.id.date_time_picker_view_date);
        mHourPicker = view.findViewById(R.id.date_time_picker_view_hour);
        mMinutePicker = view.findViewById(R.id.date_time_picker_view_minute);

        mDatePicker.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.textsize_18sp), context.getResources().getDimensionPixelSize(R.dimen.textsize_18sp));
        mHourPicker.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.textsize_18sp), context.getResources().getDimensionPixelSize(R.dimen.textsize_18sp));
        mMinutePicker.setTextSize(context.getResources().getDimensionPixelSize(R.dimen.textsize_18sp), context.getResources().getDimensionPixelSize(R.dimen.textsize_18sp));
        mDatePicker.setTopBottomPadding(context.getResources().getDimensionPixelSize(R.dimen.left_right_space));
        mHourPicker.setTopBottomPadding(context.getResources().getDimensionPixelSize(R.dimen.left_right_space));
        mMinutePicker.setTopBottomPadding(context.getResources().getDimensionPixelSize(R.dimen.left_right_space));
        mDatePicker.setSelectedTextColor(ContextCompat.getColor(context, R.color.picker_view_sel_txt_color));
        mHourPicker.setSelectedTextColor(ContextCompat.getColor(context, R.color.picker_view_sel_txt_color));
        mMinutePicker.setSelectedTextColor(ContextCompat.getColor(context, R.color.picker_view_sel_txt_color));
        mDatePicker.setUnSelectTextColor(ContextCompat.getColor(context, R.color.picker_view_un_sel_txt_color));
        mHourPicker.setUnSelectTextColor(ContextCompat.getColor(context, R.color.picker_view_un_sel_txt_color));
        mMinutePicker.setUnSelectTextColor(ContextCompat.getColor(context, R.color.picker_view_un_sel_txt_color));
        mDatePicker.setCanScrollLoop(false);
        mHourPicker.setCanScrollLoop(false);
        mMinutePicker.setCanScrollLoop(false);
        mDatePicker.setSelectedOrientation(PickerView.SELECTED_ORIENTATION_CENTER);
        mHourPicker.setSelectedOrientation(PickerView.SELECTED_ORIENTATION_CENTER);
        mMinutePicker.setSelectedOrientation(PickerView.SELECTED_ORIENTATION_CENTER);
        mDatePicker.setUseTextSizeByScale(false);
        mHourPicker.setUseTextSizeByScale(false);
        mMinutePicker.setUseTextSizeByScale(false);
        mDatePicker.setNeedChangeAlpha(false);
        mHourPicker.setNeedChangeAlpha(false);
        mMinutePicker.setNeedChangeAlpha(false);
        mDatePicker.setTextOrientation(PickerView.TEXT_ORIENTATION_RIGHT);

        mDatePicker.setLineInfo(context.getResources().getDimensionPixelSize(R.dimen.dp_45),
                context.getResources().getDimensionPixelSize(R.dimen.dp_05), ContextCompat.getColor(context, R.color.line_color));
        mHourPicker.setLineInfo(context.getResources().getDimensionPixelSize(R.dimen.dp_45),
                context.getResources().getDimensionPixelSize(R.dimen.dp_05), ContextCompat.getColor(context, R.color.line_color));
        mMinutePicker.setLineInfo(context.getResources().getDimensionPixelSize(R.dimen.dp_45),
                context.getResources().getDimensionPixelSize(R.dimen.dp_05), ContextCompat.getColor(context, R.color.line_color));

        mDatePicker.setOnSelectListener((pickerView, pickerBean, position) -> {
            if (mSelectedDayInfo == null) mSelectedDayInfo = new int[7];
            mSelectedDayInfo[0] = ((DateTimePickerBean) pickerBean).getYear();
            mSelectedDayInfo[1] = ((DateTimePickerBean) pickerBean).getMonth();
            mSelectedDayInfo[2] = ((DateTimePickerBean) pickerBean).getDay();
            mSelectedDayInfo[6] = ((DateTimePickerBean) pickerBean).getDayOfWeek();
            if (mOnSelectedListener != null)
                mOnSelectedListener.onSelected(mSelectedDayInfo);
            if (isIncludeCurrentDay && position == 0 && mPreDatePosition != 0) {
                mPreDatePosition = 0;
                changeHourList(true, true);
                changeMinuteList(true, true);
            } else if (isIncludeCurrentDay && position != 0 && mPreDatePosition == 0) {
                mPreDatePosition = position;
                changeHourList(false, false);
                changeMinuteList(false, false);
            }
        });
        mHourPicker.setOnSelectListener((pickerView, pickerBean, position) -> {
            if (mSelectedDayInfo == null) mSelectedDayInfo = new int[7];
            mSelectedDayInfo[3] = Integer.parseInt(pickerBean.getText());
            if (mOnSelectedListener != null)
                mOnSelectedListener.onSelected(mSelectedDayInfo);
            if (isIncludeCurrentDay && mPreDatePosition == 0 && position == 0 && mPreHourPosition != 0) {
                mPreHourPosition = 0;
                changeMinuteList(true, true);
            } else if (isIncludeCurrentDay && mPreDatePosition == 0 && position != 0 && mPreHourPosition == 0) {
                mPreHourPosition = position;
                changeMinuteList(false, false);
            }
        });
        mMinutePicker.setOnSelectListener((pickerView, pickerBean, position) -> {
            if (mSelectedDayInfo == null) mSelectedDayInfo = new int[7];
            mSelectedDayInfo[4] = Integer.parseInt(pickerBean.getText());
            if (mOnSelectedListener != null)
                mOnSelectedListener.onSelected(mSelectedDayInfo);
        });

        mStartDayInfo = TimeUtils.getCurrentDayInfo();

        mDatePicker.setVisibility(isShowDate ? View.VISIBLE : View.GONE);
    }

    public void onDestroy() {
        mDatePicker.onDestroy();
        mHourPicker.onDestroy();
        mMinutePicker.onDestroy();
    }

    public void setOnSelectedListener(OnSelectedListener onSelectedListener) {
        mOnSelectedListener = onSelectedListener;
    }

    public void setIncludeCurrentDay(boolean includeCurrentDay) {
        this.isIncludeCurrentDay = includeCurrentDay;
    }

    public void refreshStartDayInfo(int[] startDayInfo) {
        mStartDayInfo = startDayInfo;
    }

    public void refreshEndDayInfo(int[] endDayInfo) {
        mEndDayInfo = endDayInfo;
    }

    public void clearSelected() {
        mSelectedDayInfo = null;
    }

    public void clearLimit() {
        mStartDayInfo = TimeUtils.getCurrentDayInfo();
        mEndDayInfo = null;
    }

    // 格式：  HH:mm
    public void selectTime(String time) {
        if (TextUtils.isEmpty(time)) return;
        String[] timeSplit = time.split(":");
        for (PickerBean pickerBean : mHourPicker.getDataList()) {
            if (pickerBean.getText().equals(timeSplit[0])) {
                mHourPicker.setSelected(mHourPicker.getDataList().indexOf(pickerBean));
                break;
            }
        }
        for (PickerBean pickerBean : mMinutePicker.getDataList()) {
            if (pickerBean.getText().equals(timeSplit[1])) {
                mMinutePicker.setSelected(mMinutePicker.getDataList().indexOf(pickerBean));
                break;
            }
        }
    }

    @Override
    public void setVisibility(int visibility) {
        if (visibility == View.VISIBLE) {
            refresh();
        }
        super.setVisibility(visibility);
    }

    private void refresh() {
        ArrayList<DateTimePickerBean> dateList = getDateList(mStartDayInfo, mEndDayInfo);
        if (!isIncludeCurrentDay && CollectionUtils.isNotEmpty(dateList))
            dateList.remove(0);
        mDatePicker.setDataList(new ArrayList<>(dateList));

        ArrayList<StringPickerBean> hourList, minuteList;
        if (isIncludeCurrentDay) {
            hourList = getHourList(mSelectedDayInfo == null || mSelectedDayInfo[0] == mStartDayInfo[0] &&
                    mSelectedDayInfo[1] == mStartDayInfo[1] && mSelectedDayInfo[2] == mStartDayInfo[2] ? mStartDayInfo[3] : 0, 24);
            minuteList = getMinuteList(mSelectedDayInfo == null || mSelectedDayInfo[0] == mStartDayInfo[0] &&
                    mSelectedDayInfo[1] == mStartDayInfo[1] && mSelectedDayInfo[2] == mStartDayInfo[2] ? mStartDayInfo[3] : 0, 60);
        } else {
            hourList = getHourList(0, 24);
            minuteList = getMinuteList(0, 60);
        }
        mHourPicker.setDataList(new ArrayList<>(hourList));
        mMinutePicker.setDataList(new ArrayList<>(minuteList));

        if (mSelectedDayInfo != null) {
            for (DateTimePickerBean dateTimePickerBean : dateList) {
                if (dateTimePickerBean.getYear() == mSelectedDayInfo[0] &&
                        dateTimePickerBean.getMonth() == mSelectedDayInfo[1] &&
                        dateTimePickerBean.getDay() == mSelectedDayInfo[2]) {
                    mDatePicker.setSelected(dateList.indexOf(dateTimePickerBean));
                    break;
                }
            }
            for (StringPickerBean stringPickerBean : hourList) {
                if (Integer.parseInt(stringPickerBean.getText()) == mSelectedDayInfo[3]) {
                    mHourPicker.setSelected(hourList.indexOf(stringPickerBean));
                    break;
                }
            }
            for (StringPickerBean stringPickerBean : minuteList) {
                if (Integer.parseInt(stringPickerBean.getText()) == mSelectedDayInfo[4]) {
                    mMinutePicker.setSelected(minuteList.indexOf(stringPickerBean));
                    break;
                }
            }
        } else {
            mSelectedDayInfo = new int[7];
            mSelectedDayInfo[0] = dateList.get(0).getYear();
            mSelectedDayInfo[1] = dateList.get(0).getMonth();
            mSelectedDayInfo[2] = dateList.get(0).getDay();
            mSelectedDayInfo[6] = dateList.get(0).getDayOfWeek();
            mSelectedDayInfo[3] = Integer.parseInt(hourList.get(0).getText());
            mSelectedDayInfo[4] = Integer.parseInt(minuteList.get(0).getText());
            if (mOnSelectedListener != null)
                mOnSelectedListener.onSelected(mSelectedDayInfo);
        }
    }

    private void changeHourList(boolean needLimit, boolean isMin) {
        ArrayList<StringPickerBean> hourList;
        if (!needLimit)
            hourList = getHourList(0, 24);
        else {
            if (isMin) {
                hourList = getHourList(TimeUtils.getCurrentDayInfo()[3], 24);
            } else {
                hourList = getHourList(0, mEndDayInfo != null ? mEndDayInfo[3] : 24);
            }
        }
        mHourPicker.setDataList(new ArrayList<>(hourList));
        mSelectedDayInfo[3] = Integer.parseInt(hourList.get(0).getText());
        if (mOnSelectedListener != null)
            mOnSelectedListener.onSelected(mSelectedDayInfo);
    }

    private void changeMinuteList(boolean needLimit, boolean isMin) {
        List<StringPickerBean> minuteList;
        if (!needLimit)
            minuteList = getMinuteList(0, 60);
        else {
            if (isMin) {
                minuteList = getMinuteList(TimeUtils.getCurrentDayInfo()[4], 60);
            } else {
                minuteList = getMinuteList(0, mEndDayInfo != null ? mEndDayInfo[4] : 60);
            }
        }
        mMinutePicker.setDataList(new ArrayList<>(minuteList));
        mSelectedDayInfo[4] = Integer.parseInt(minuteList.get(0).getText());
        if (mOnSelectedListener != null)
            mOnSelectedListener.onSelected(mSelectedDayInfo);
    }

    private ArrayList<DateTimePickerBean> getDateList(int[] startDayInfo, int[] endDayInfo) {
        int currentYear = TimeUtils.getCurrentYear();
        if (startDayInfo == null) startDayInfo = TimeUtils.getCurrentDayInfo();
        ArrayList<DateTimePickerBean> dateList = new ArrayList<>();
        int dayOfWeek = startDayInfo[6];
        int cYear = startDayInfo[0], cMonth = startDayInfo[1], cDay = startDayInfo[2] - 1, cDayOfWeek;
        String dayStr, dayOfWeekStr = "";
        int maxDay;
        int count = 1000;
        for (int i = 0; i < count; i++) {
            maxDay = TimeUtils.getTotalDayOfMonth(cYear, cMonth);
            cDay++;
            if (cDay > maxDay) {
                cDay = 1;
                cMonth += 1;
                if (cMonth > 12) {
                    cMonth = 1;
                    cYear += 1;
                }
            }
            if (cDay < 10)
                dayStr = "0" + cDay;
            else
                dayStr = String.valueOf(cDay);
            cDayOfWeek = (dayOfWeek + i) % 7;
            switch (cDayOfWeek) {
                case Calendar.MONDAY:
                    dayOfWeekStr = "一";
                    break;
                case Calendar.TUESDAY:
                    dayOfWeekStr = "二";
                    break;
                case Calendar.WEDNESDAY:
                    dayOfWeekStr = "三";
                    break;
                case Calendar.THURSDAY:
                    dayOfWeekStr = "四";
                    break;
                case Calendar.FRIDAY:
                    dayOfWeekStr = "五";
                    break;
                case 0:
                    dayOfWeekStr = "六";
                    break;
                case Calendar.SUNDAY:
                    dayOfWeekStr = "日";
                    break;
            }
            DateTimePickerBean dateInfo = new DateTimePickerBean();
            dateInfo.setYear(cYear)
                    .setMonth(cMonth)
                    .setDay(cDay)
                    .setDayOfWeek(cDayOfWeek)
                    .setDayOfWeekStr(String.format("周%s", dayOfWeekStr))
                    .setTextSpace(getContext().getResources().getDimensionPixelSize(R.dimen.toolbar_height));
            if (cYear == currentYear)
                dateInfo.setDate(String.format("%s月%s日", cMonth, dayStr));
            else
                dateInfo.setDate(String.format("%s年%s月%s日", cYear, cMonth, dayStr));

            if (endDayInfo != null &&
                    (cYear > endDayInfo[0] ||
                            cYear == endDayInfo[0] && cMonth > endDayInfo[1] ||
                            cYear == endDayInfo[0] && cMonth == endDayInfo[1] && cDay >= endDayInfo[2]))
                break;
            else
                dateList.add(dateInfo);
        }
        return dateList;
    }

    @SuppressLint("DefaultLocale")
    private ArrayList<StringPickerBean> getHourList(int minHour, int maxHour) {
        ArrayList<StringPickerBean> hourList = new ArrayList<>();
        for (; minHour < maxHour; minHour++) {
            hourList.add(new StringPickerBean().setText(String.format("%02d", minHour)));
        }
        return hourList;
    }

    @SuppressLint("DefaultLocale")
    private ArrayList<StringPickerBean> getMinuteList(int minMinute, int maxHour) {
        ArrayList<StringPickerBean> minuteList = new ArrayList<>();
        for (; minMinute < maxHour; minMinute++) {
            minuteList.add(new StringPickerBean().setText(String.format("%02d", minMinute)));
        }
        return minuteList;
    }

    public interface OnSelectedListener {
        void onSelected(int[] selectedDayInfo);
    }
}
